<?php
namespace App\Repositories;

use App\Traits\SingletonTrait;
use Psr\Container\ContainerInterface;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Di\Annotation\Inject;

abstract class AbstractRepository implements InterfaceRepository
{
    protected $container;

    public $model;

    public function __construct() {
        $this->container = ApplicationContext::getContainer();
        $this->initModel();
    }

    abstract function model();

    public function initModel()
    {
        $this->model = $this->container->get($this->model());
    }

    public function getTableName()
    {
        return $this->model->getTable();
    }

    public function success($data)
    {
        return [
            'success' => true,
            'data' => $data
        ];
    }

    public function error($msg,$data=[])
    {
        return [
            'success' => false,
            'msg' => $msg,
            'data' => $data
        ];
    }

    public function all($columns="*",$where=[],$orderBy='')
    {
        $query = $this->model::query();
        if(!empty($where)){
            foreach ($where as $key=>$value)
            {
                $field = $value['field'];
                $s_value = $value['value'];
                $method = isset($value['method'])?$value['method']:null;
                switch ($method){
                    case 'in':
                        $query->whereIn($field,$s_value);
                        break;
                    case 'like':
                        $query->where($field,'like','%'.$s_value.'%');
                        break;
                    default:
                        $query->where($field,$s_value);
                }
            }
        }
        if(is_array($orderBy)&&!empty($orderBy)){
            foreach ($orderBy as $orderItem){
                $query->orderBy($orderItem['field'],$orderItem['sort']);
            }
        }
        $data = $query->select($columns)->get();
        return $data;
    }

    public function getById($id)
    {
        return $this->model->find($id);
    }

    public function first($columns,$where)
    {

    }

    public function one($columns,$where,$orderBy='')
    {
        $query = $this->model::query();
        if(!empty($where)){
            foreach ($where as $key=>$value)
            {
                $field = $value['field'];
                $s_value = $value['value'];
                $method = isset($value['method'])?$value['method']:'=';
                switch ($method){
                    case 'in':
                        $query->whereIn($field,$s_value);
                        break;
                    case 'like':
                        $query->where($field,'like','%'.$s_value.'%');
                        break;
                    default:
                        $query->where($field,$method,$s_value);
                }
            }
        }
        if(is_array($orderBy)&&!empty($orderBy)){
            foreach ($orderBy as $orderItem){
                $query->orderBy($orderItem['field'],$orderItem['sort']);
            }
        }
        $data = $query->select($columns)->first();
        return $data;
    }

    public function count($field,$where)
    {
        $query = $this->model::query();
        if(!empty($where)){
            foreach ($where as $key=>$value)
            {
                $field = $value['field'];
                $s_value = $value['value'];
                $method = isset($value['method'])?$value['method']:null;
                switch ($method){
                    case 'in':
                        $query->whereIn($field,$s_value);
                        break;
                    case 'like':
                        $query->where($field,'like','%'.$s_value.'%');
                        break;
                    default:
                        $query->where($field,$s_value);
                }
            }
        }
        $data = $query->count($field);
        return $data;
    }

    public function delete($id)
    {
        $model = $this->getById($id);
        return $model->delete();
    }

    public function deleteAll($search=[])
    {
        $query = $this->model::query();
        if(!empty($search)){
            foreach ($search as $key=>$value)
            {
                $field = $value['field'];
                $s_value = $value['value'];
                $method = isset($value['method'])?$value['method']:null;
                switch ($method){
                    case 'notin':
                        $query->whereNotIn($field,$s_value);
                        break;
                    case 'in':
                        $query->whereIn($field,$s_value);
                        break;
                    case 'like':
                        $query->where($field,'like','%'.$s_value.'%');
                        break;
                    default:
                        if($method){
                            $query->where($field,$method,$s_value);
                        }else{
                            $query->where($field,$s_value);
                        }

                }
            }
        }
        return $query->delete();
    }

    public function store($data)
    {
        $model = isset($data['id'])&&$data['id']?$this->getById($data['id']):new $this->model();
        $model->fill($data);
        if(!$model->save()){
            return $this->error('保存失败');
        }
        return $this->success($model);
    }

    public function update($update,$where){
        $query = $this->model::query();
        if(!empty($where)){
            foreach ($where as $key=>$value)
            {
                $field = $value['field'];
                $s_value = $value['value'];
                $method = isset($value['method'])?$value['method']:null;
                switch ($method){
                    case 'in':
                        $query->whereIn($field,$s_value);
                        break;
                    case 'like':
                        $query->where($field,'like','%'.$s_value.'%');
                        break;
                    default:
                        $query->where($field,$s_value);
                }
            }
        }
        return $query->update($update);
    }

    /**
     * @param string $columns
     * @param array $search [['field'=>'','value'=>'','method'=>'']]
     * @param  $page
     * @return mixed
     */
    public function getList($columns="*",array $search=[],$page,$orderBy='',$join='',$with='',$groupby=[])
    {
        $query = $this->model::query()->select($columns);
        if(!empty($with)){
            $query->with($with);
        }
        if(is_array($orderBy)&&!empty($orderBy)){
            foreach ($orderBy as $orderItem){
                if(isset($orderItem['sort'])){
                    $query->orderBy($orderItem['field'],$orderItem['sort']);
                }else{
                    $query->orderBy($orderItem['field']);
                }

            }
        }
        if(!empty($search)){
            foreach ($search as $key=>$value)
            {
                $field = $value['field'];
                $s_value = $value['value'];
                $method = isset($value['method'])?$value['method']:null;
                switch ($method){
                    case 'notin':
                        $query->whereNotIn($field,$s_value);
                        break;
                    case 'in':
                        $query->whereIn($field,$s_value);
                        break;
                    case 'like':
                        $query->where($field,'like','%'.$s_value.'%');
                        break;
                    default:
                        if($method){
                            $query->where($field,$method,$s_value);
                        }else{
                            $query->where($field,$s_value);
                        }

                }
            }
        }
        if(is_array($join)&&!empty($join)){
            foreach ($join as $key=>$joinItem){
                $query->join($key,function($join) use($joinItem){
                    $join->on($joinItem['on'][0],$joinItem['on'][1],$joinItem['on'][2]);
                    if(isset($joinItem['where'])&&!empty($joinItem['where'])){
                        foreach ($joinItem['where'] as $where){
                            $field = $where['field'];
                            $s_value = $where['value'];
                            $method = isset($where['method'])?$where['method']:null;
                            switch ($method){
                                case 'notin':
                                    $join->whereNotIn($field,$s_value);
                                    break;
                                case 'in':
                                    $join->whereIn($field,$s_value);
                                    break;
                                case 'like':
                                    $join->where($field,'like','%'.$s_value.'%');
                                    break;
                                case 'null':
                                     $join->whereNull($field);
                                    break;
                                case 'notnull':
                                    $join->whereNotNull($field);
                                    break;
                                default:
                                    if($method){
                                        $join->where($field,$method,$s_value);
                                    }else{
                                        $join->where($field,$s_value);
                                    }

                            }
                        }
                    }
                });
            }
        }
        if(!empty($groupby)){
            $query->groupBy($groupby);
        }
        if(is_array($page)&&!empty($page)){
            $result = $query->paginate((int)$page['limit']);
            return $this->splitPage($result);
        }
        if(!is_array($page)&&$page){
            $query->take($page);
        }
        return $query->get();
    }

    public function splitPage($result)
    {
        $return = [];
        $result = $result->toArray();
        $return['result'] = $result['data'];
        $return['page'] = [
            "current_page"=>$result['current_page'],
            "first_page_url"=>$result['first_page_url'],
            "from"=>$result['from'],
            "last_page"=>$result['last_page'],
            "last_page_url"=>$result['last_page_url'],
            "next_page_url"=>$result['next_page_url'],
            "path"=>$result['path'],
            "per_page"=>$result['per_page'],
            "prev_page_url"=>$result['prev_page_url'],
            "to"=>$result['to'],
            "total"=>$result['total']
        ];
        return $return;
    }
}
